/// esta clase es el partido, actua como un juez, si 
/// se le pasa una jugada (golpe) el lleva el estado del partido.

class Partido {

  ArrayList<Punto> puntos;  // puntos del partido, cada uno con sus trayectorias
  private Punto puntoActual;
  private Golpe lastGolpe;

  int puntoEnEdicion = 0;
  int golpeEnEdicion = 0;

  Boolean edicion;  // true,  modo edicion que permite navegar, 
                    // false, modo de añadir, a partir del ultimo frame

  Partido() {
    puntos = new ArrayList<Punto>();
    golpes = new  ArrayList<Golpe>();
    lastGolpe = null;

    // try to load late games:   
    if (loadFicheroPartido(LOADPATH)) {
      println ("FICHERO CARGADO");
    }
    else {
      println (" ---------  CARGADOS ------");
      for (int i=0; i < golpes.size(); i++)
        println ("   "+ golpes.get(i));
    }
  }

  // durante la operacion del programa,se llama a este
  Boolean siguienteGolpe(Golpe g) {
    return addGolpe (g, false);
  }

  // es posible llamar a esto pero solo desde la lectura de backup
  private Boolean addGolpe (Golpe g, Boolean backup) {

    Boolean valido = true;

    // estos son los estados :  "Saque", "Suelo", "Raqueta", "Red", "Punto Dentro", "Punto Fuera"
    lastGolpe = g;

    if (backup) { // si estamos leyendo el backup
      golpes.add(g);
      println ("add golpe:" + g);
    }

    switch (g.getTipo() ) {
    case 0: // es saque
      if (puntoActual == null) {
        // println ("saque");
        puntoActual = new Punto();
        puntoActual.addGolpeAPunto(g);
      }
      else
        valido = false;
      break;

    case 1:  // suelo
    case 2:  // raqueta
    case 3:  // red
      println ("   ----   continua   -----  ");    

      if (puntoActual != null) {

        puntoActual.addGolpeAPunto(g);
      }
      else
        valido = false;
      break;

    case 4:  // punto Player A
    case 5:  // punto Player B
      if (puntoActual != null) {
        //  println ("punto!!!");
        puntoActual.addGolpeAPunto(g);
        puntos.add (puntoActual);
        if (!backup)
          puntoActual.cierraPunto();

        puntoActual = null;
        // hacer el backup
        if (!backup)
          guardaFicheroPartido(OUTPATH);
      }
      else
        valido = false;
      break;
    }  

    return valido;
  }

  int getNumeroPuntos() {
    return puntos.size();
  }

  void pintaGolpesPunto() {
    if (puntoActual != null) {
      stroke (0);
      puntoActual.pintaGolpesPunto(true);
    }
  }

  void pintaGolpesPartido() {
    stroke (127);  
    // solo se previsualizan los ultimos 5 puntos
    int inicio =0;
    if (puntos.size() > 5)
      inicio = puntos.size() -5;

    for (int i=inicio; i< puntos.size(); i++) { 
      if (i== puntos.size()-1)
        puntos.get(i).pintaGolpesPunto(true);
      else
        puntos.get(i).pintaGolpesPunto(false);
    }
  }

  void pintaTrayectoriasPunto (int punto, Golpe golpe) {
    if (puntos.size()>punto) {
      Punto aux = puntos.get(punto);
      for (int i=0; i< aux.trayectorias.size(); i++) {
        if (aux.trayectorias.get(i).inicio.equals(golpe))
          aux.trayectorias.get(i).pinta (golpe, true);
        else
          aux.trayectorias.get(i).pinta (golpe, false);
      }
    }
  }

  Boolean loadFicheroPartido(String path) {
    String linea;

    int state = 0;  // 0-> nada, 1-> punto, 2-> en golpes punto, 3 en trayectorias
    
    int lastSaque = 0;

    BufferedReader reader = createReader(path);
    if (reader == null)
      return false;

    Boolean valido = false;

    try {
      linea = reader.readLine();
    } 
    catch (IOException e) {
      return false;
    }

    println("========================");
    println("Cargando partido salvado");

    valido = true;
    while (linea != null) {
      try {

        if (linea.equals("---- PUNTO ----")) {
          state = 1;
        }
        else if (linea.equals("---- FIN PUNTO ----")) {
          //println ( puntos.get(puntos.size()-1));
          println ("-- punto cargado --");
          state = 0;
        }
        else if (linea.equals("---- GOLPES PUNTO ----")) {
          state = 2;
        }
        else if (state == 1){  // quien saca!
          String[] ls = split(linea, ' ');
          
          if (ls.length != 2)
              println ("saque erroneo");

          println ("saca "+ tJugador[0]);                            
          if (ls[1].equals (tJugador[0]))
             lastSaque = 0;
          else if (ls[1].equals (tJugador[1]))
             lastSaque = 1;
          else
              println ("saque erroneo");
          
        }else if (linea.equals("---- GOLPES TRAYECTORIA ----")) {
          state = 3;
        }          
        else if (state == 2) {  /////////////////////   GOLPE 

          Golpe g = new Golpe (linea);
          if (!this.addGolpe(g, true))
            println ("ERROR cargando fichero");
        }
        else if (state == 3) {  ///////////////////   TRAYECTORIA 

          // inicio:(Saque pos:[ 306.0, 0.0, 598.0 ] frame:35011) fin(Raqueta pos:[ 185.0, 0.0, 212.0 ] frame:35011) v:[ 0.0, 0.5, 1.0 ]
          String cads[] = match (linea, "\\(.*\\) fin");
          if (cads == null) {
            println ("error cargando fichero");
            return false;
          }
          String sp0= cads[0].substring(1, cads[0].length()-5);
          // println (sp0);

          cads = match (linea, "fin\\(.*\\) v\\:");  
          if (cads == null) {
            println ("error cargando fichero");
            return false;
          }
          String sp1= cads[0].substring(4, cads[0].length()-4); 

          cads = match (linea, "v\\:.*");  
          String pv= cads[0].substring(3, cads[0].length()-1);

          String[] pvp = split(pv, ',');
          float x = parseFloat (pvp[0]);
          float y = parseFloat (pvp[1]);
          float z = parseFloat (pvp[2]);

          Golpe p0 = new Golpe(sp0);
          Golpe p1 = new Golpe(sp1); 
          PVector v = new PVector(x, y, z);

          Punto last = puntos.get(puntos.size()-1);
          Golpe g0 = null;
          Golpe g1 = null;
          for (int i=0; i < last.golpes.size(); i++) {
            if (last.golpes.get(i).equals(p0)) {
              g0 = last.golpes.get(i);
              break;
            }
          }
          for (int i=0; i < last.golpes.size(); i++) {
            if (last.golpes.get(i).equals(p1)) {
              g1 = last.golpes.get(i);
              break;
            }
          }

          if ((g0 == null)||( g1 == null)) {
            println ("error: cargando trayectorias");
            println ("   no encuentra "+ p0);
            println ("o  no encuentra "+ p1);

            for (int i=0; i < last.golpes.size(); i++)
              println ("-- "+ last.golpes.get(i));
            return false;
          }

          last.addTrayectoria(new Trayectoria(g0, g1, v));
          if (lastSaque != -1){
            last.jugadorQueSaca = lastSaque;
            last.golpes.get(0).jugador = lastSaque;
            last.updateJugador();
          }
        }

        linea = reader.readLine();
      } 
      catch (IOException e) {
        println ("algun error en el camino");
        break;
      }
    }  
    return valido;
  }

  void deleteLastGolpe() {
    if (puntoActual == null) {
      if (puntos.size() == 0)
        return;
      puntoActual = puntos.get(puntos.size()-1);
    }

    puntoActual.borraTrayectorias();

    if (puntoActual.golpes.size() > 1) {
      lastGolpe= puntoActual.golpes.get(puntoActual.golpes.size()-1);
      puntoActual.golpes.remove(puntoActual.golpes.size()-1);
    }
    else if (puntoActual.golpes.size() == 1) {
      println ("last!");
      puntoActual.golpes.remove(puntoActual.golpes.size()-1);
      puntoActual = null;
      puntos.remove(puntos.size()-1);
    }
    else
      println ("punto vacio!");
  }

  int getNumPuntos() {
    return  puntos.size();
  } 

  int  getGolpesPuntoEnEdicion() {
    if (puntoEnEdicion < puntos.size())
      return puntos.get(puntoEnEdicion).golpes.size();
    else   
      return 0;
  }

  int getFrameGolpeEnEdicion() {
    if ((puntoEnEdicion < puntos.size()) && (puntos.get(puntoEnEdicion).golpes.size() > 0))
      return int(puntos.get(puntoEnEdicion).golpes.get(golpeEnEdicion).frame);
    else
      return 0;
  }

  PVector getGolpeEnEdicionPos() {
    if ((puntoEnEdicion < puntos.size()) && (puntos.get(puntoEnEdicion).golpes.size() > 0))
      return partido.puntos.get(puntoEnEdicion).golpes.get(golpeEnEdicion).pos;
    else
      return new PVector(0, 0, 0);
  }

  Golpe getGolpe(int p, int g) {
    if (puntos.size()>p) 
      if (puntos.get(p).golpes.size()>g) {
        return puntos.get(p).golpes.get(g);
      }
    return null;
  }
  
  Trayectoria getTrayectoria(int p, int t) {

    if (puntos.size()>p) 
      if (puntos.get(p).trayectorias.size()>t) {
        return puntos.get(p).trayectorias.get(t);
      }
    println("Error: no existe la trayectoria "+t+" en "+p);  
    return null;
  }

  Trayectoria getTrayectoriaByGolpe(int p, Golpe g) {
    if (puntos.size()>p) {
      Punto aux = puntos.get(p);
      for (int i=0; i< aux.trayectorias.size(); i++) {
        if (aux.trayectorias.get(i).inicio.equals(g))
          return aux.trayectorias.get(i);
      } 
      println ("Error: no existe el punto "+g+" en "+p);
    }
    println ("Error");
    return null;
  }

  Trayectoria getTrayectoriaAnterior(int p, Trayectoria tr) {

    Trayectoria anterior = null;

    if (puntos.size()>p) {
      Punto aux = puntos.get(p);

      for (int i=0; i< aux.trayectorias.size(); i++) {
        if (aux.trayectorias.get(i) == tr)
          return anterior;
        anterior = aux.trayectorias.get(i);
      } 
      println ("Error: no existe trayectoria "+tr+" en "+p);
    }
    println ("Error");
    return null;
  }

  void frameUpdate(int gotoFrame) {//busca el golpe más próximo a gotoFrame
    if (estadoAplicacion==2 && true)
    {
       for (int i=0; i<puntos.size(); i++) {
        Punto p = puntos.get(i);
        for (int j=0; j<p.trayectorias.size(); j++) {
          Trayectoria tr = p.trayectorias.get(j); 
          if (((tr.inicio.frame-1)<gotoFrame) && ((tr.fin.frame+1)>gotoFrame)) {
            puntoEnEdicion=i;
            golpeEnEdicion=j;
            return;
          }
        }
      }
    }
  }
  
 int getQuienSaca(){
   return  partido.puntos.get(puntoEnEdicion).golpes.get(0).jugador;   
  }

 int getJugador(int i){
   return partido.puntos.get(puntoEnEdicion).golpes.get(i).jugador;
 }  
}

